package org.zch.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zch.common.enums.SignTodayEnum;
import org.zch.common.enums.SignTomorrowEnum;
import org.zch.common.utils.TimerSetUtils;
import org.zch.dao.UserDAO;
import org.zch.dao.UserWorksDAO;
import org.zch.entity.po.UserInfoPO;
import org.zch.entity.vo.*;
import org.zch.service.FileService;
import org.zch.service.MessageService;
import org.zch.service.UserService;
import org.zch.service.WorksService;
import org.zch.common.utils.CodeNoUtil;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 用户信息
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDAO userDao;

    @Autowired
    private CodeNoUtil codeNoUtil;

    @Autowired
    private WorksService worksService;
    @Autowired
    private UserWorksDAO userWorksDAO;
    @Autowired
    private MessageService messageService;
    @Autowired
    private FileService fileService;

    @Override
    public AllUserDataVO search(UserInfoPO userInfoPO) {
        AllUserDataVO allUserDataVO = new AllUserDataVO();
        allUserDataVO.setAllNum(0);
        allUserDataVO.setNowNum(0);
        LambdaQueryWrapper<UserInfoPO> queryWrapper = UserInfoPO.getQueryWrapper();
        if (ObjectUtil.isNull(userInfoPO)) {
            return allUserDataVO;
        }
        queryWrapper
                .eq(StrUtil.isNotEmpty(userInfoPO.getMac()), UserInfoPO::getMac, userInfoPO.getMac())
                .eq(StrUtil.isNotEmpty(userInfoPO.getCode()), UserInfoPO::getCode, userInfoPO.getCode())
                .like(StrUtil.isNotEmpty(userInfoPO.getName()), UserInfoPO::getName, userInfoPO.getName())
                .eq(ObjectUtil.isNotEmpty(userInfoPO.getSex()), UserInfoPO::getSex, userInfoPO.getSex());
        queryWrapper.orderByDesc(UserInfoPO::getCreateTime);
        List<UserInfoPO> userInfoPOS = userDao.selectList(queryWrapper);

        allUserDataVO.setAllNum(userInfoPOS.size());
        int nowNumber = 0;
        for (UserInfoPO user: userInfoPOS){
            if (TimerSetUtils.isYesterday(user.getCreateTime())){
                nowNumber ++;
            }
        }
        allUserDataVO.setNowNum(nowNumber);
        return allUserDataVO;
    }


    /**
     * 根据code获取用户信息
     *
     * @param code 用户code
     * @return
     */
    @Override
    public UserInfoVO getByCode(String code) {
        UserInfoVO infoVO = new UserInfoVO();
        // 用户信息
        LambdaQueryWrapper<UserInfoPO> queryWrapper = UserInfoPO.getQueryWrapper();
        queryWrapper.eq(UserInfoPO::getCode, code);
        UserInfoPO infoPO = userDao.selectOne(queryWrapper);
        if (infoPO != null){
            // 作品数量
            WorksByUserVO worksQuantity = worksService.getWorksQuantityByUserCode(infoPO.getCode());
            int workNum = 0;
            if (worksQuantity != null){
                workNum = worksQuantity.getAwaitNum() + worksQuantity.getPassNum() + worksQuantity.getRefuseNum();
            }
            // 点赞作品数量
            WorksByUserVO countWorks = userWorksDAO.countWorks(infoPO.getId());
            // 被赞数量
            int likedNum = worksService.beenLikedNum(code) == null ? 0 : worksService.beenLikedNum(code);
            // 语音播放量
            int beenVoiceNum = worksService.beenVoiceNum(code) == null ? 0 : worksService.beenVoiceNum(code);
            // 是否有未读消息
            Integer haveUnreadMsg = messageService.haveUnreadMsg(code);
            // 返回类
            BeanUtils.copyProperties(infoPO, infoVO);
            infoVO.setWorkNum(workNum);
            infoVO.setLookNum(countWorks.getLookNum());
            infoVO.setLikedNum(countWorks.getLikedNum());
            infoVO.setBeenLikedNum(likedNum);
            infoVO.setBeenVoiceNum(beenVoiceNum);
            infoVO.setHaveUnreadMsg(haveUnreadMsg);
        }

        return infoVO;
    }

    @Override
    public String getUserAddressById(String code) {
        LambdaQueryWrapper<UserInfoPO> queryWrapper = UserInfoPO.getQueryWrapper();
        queryWrapper.eq(UserInfoPO::getCode, code);
        return userDao.selectOne(queryWrapper).getAddress();
    }

    @Override
    public String getUserPhoneById(String code) {
        LambdaQueryWrapper<UserInfoPO> queryWrapper = UserInfoPO.getQueryWrapper();
        queryWrapper.eq(UserInfoPO::getCode, code);
        return userDao.selectOne(queryWrapper).getPhone();
    }

    @Override
    public Integer getUserLaoNumByCode(String code) {
        LambdaQueryWrapper<UserInfoPO> queryWrapper = UserInfoPO.getQueryWrapper();
        queryWrapper.eq(UserInfoPO::getCode, code);
        return userDao.selectOne(queryWrapper).getLaoNum();
    }


    @Override
    public Integer setUserLaoNumByCode(UserInfoPO updatePO) {
        String code = updatePO.getCode();
        LambdaQueryWrapper<UserInfoPO> queryWrapper = UserInfoPO.getQueryWrapper();
        queryWrapper.eq(UserInfoPO::getCode, code);
        Integer laoNum = updatePO.getLaoNum() + userDao.selectOne(queryWrapper).getLaoNum();
        UserInfoPO userInfoPO = new UserInfoPO();
        userInfoPO.setCode(code);
        userInfoPO.setLaoNum(laoNum);
        return userDao.update(userInfoPO);
    }


    /**
     * 判断是否为新用户
     */
    @Override
    public NewUserVO getUserBean(String mac) {
        NewUserVO mR = new NewUserVO();
        UserInfoPO userPO = userDao.getUserByMac(mac);
        if (null == userPO) {
            mR.setGetNew(true);
        } else {
            mR.setGetNew(false);
            mR.setUserID(userPO.getCode());
            mR.setHasOut(userPO.getHasOut() != null && userPO.getHasOut());
        }
        return mR;
    }

    /**
     * 创建新用户
     *
     * @param mac 设备码
     * @return
     */
    @Async
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String setNewUser(String mac) {
        // 解密mac todo
        // 通过 mac查询用户
        String userID = "";
        UserInfoPO userPO = userDao.getUserByMac(mac);
        if (null == userPO) {
            // 没有这个用户，则进行注册
            userPO = new UserInfoPO();
            String mCode = codeNoUtil.getUserCode();
            userID = mCode;
            userPO.setCode(mCode);
            userPO.setName("话唠" + mCode);
            userPO.setMac(mac);
            //随机性别，以及头像和性别挂钩
            Integer mS = 0;
            String mH = "http://hualao.icu/images/sex0.png";
            if ((int) ((Math.random() * 10)) > 5){
                //男
                mS = 1;
                mH = "http://hualao.icu/images/sex1.png";
            }
            userPO.setSex(mS);
            userPO.setGetNum(0);
            userPO.setPlayNum(0);
            userPO.setHeadPic(mH);
            userPO.setLaoNum(10);
            userPO.setLaoMoney(0);
            userPO.setLikeNum(0);
            userPO.setSignNumber(0);
            userPO.setSkin("");
            userPO.setCreateTime(new Date());
            int mY = Calendar.getInstance().get(Calendar.YEAR);
            int mM = Calendar.getInstance().get(Calendar.MONTH) + 1;
            int mD = Calendar.getInstance().get(Calendar.DATE);
            userPO.setOld(mY + "-" + mM + "-" + mD);
            userDao.insert(userPO);
        } else {
            userID = userPO.getCode();
        }
        return userID;
    }

    /**
     * 根据用户mac获取用户id
     *
     * @param mac 设备码
     * @return id 用户id
     */
    @Override
    public Integer getUserIdByMac(String mac) {
        UserInfoPO userPO = this.getUserByMac(mac);
        if (userPO == null) {
            return null;
        }
        return userPO.getId();
    }

    @Override
    public UserInfoPO getUserByMac(String mac) {
        LambdaQueryWrapper<UserInfoPO> queryWrapper = UserInfoPO.getQueryWrapper();
        queryWrapper.eq(UserInfoPO::getMac, mac);
        return userDao.selectOne(queryWrapper);
    }


    /**
     * @param userInfoPO
     * @return
     */
    @Override
    public Integer update(UserInfoPO userInfoPO) {
        return userDao.update(userInfoPO);
    }


    /**
     * 排行榜
     */
    @Override
    public RankingVO getUserRanking(String code) {
        List<UserInfoPO> userRanking = userDao.getUserRanking();
        RankingVO ranking = new RankingVO();
        ranking.setUserList(userRanking);
        //我的位置
        int mR = -1;
        for (int i = 0; i < userRanking.size(); i++) {
            UserInfoPO mU = userRanking.get(i);
            if (Objects.equals(mU.getCode(), code)) {
                mR = i + 1;
                ranking.setName(mU.getName());
                ranking.setHeadPic(mU.getHeadPic());
                ranking.setLaoMoney(mU.getLaoMoney());
            }
        }
        ranking.setRanking(mR);
        if (mR == -1) {
            UserInfoPO byCode = getByCode(code);
            if (byCode != null) {
                ranking.setName(byCode.getName());
                ranking.setHeadPic(byCode.getHeadPic());
                ranking.setLaoMoney(byCode.getLaoMoney());
            }
        }
        return ranking;
    }


    @Override
    public Integer setUserSign(String code, Integer signNum) {
        UserInfoPO userInfoPO = new UserInfoPO();
        userInfoPO.setCode(code);
        userInfoPO.setSignTime(new Date());
        userInfoPO.setSignNumber(signNum + 1);
        Integer i = userDao.update(userInfoPO);
        if (i == 1) {
            //签到成功，给用户奖励
            int addMoney = signNum > 3 ? 5 : signNum + 1;
            updateLaoMoney(code, addMoney);

            /*UserInfoPO byCode = getByCode(code);
            if (byCode != null) {
                Integer laoM = byCode.getLaoMoney();
                if (laoM == null) {
                    laoM = 0;
                }
                addMoney = laoM + addMoney;
                updateLaoMoney(code, addMoney);
            }*/
        }
        return i;
    }

    /**
     * 变更金额
     *
     * @param userCode     用户编码
     * @param changeValues 变化数值
     * @return
     */
    @Override
    public Integer updateLaoMoney(String userCode, Integer changeValues) {
        return userDao.updateLaoMoney(userCode, changeValues);
    }

    /**
     * 根据用户code，批量查询用户信息
     *
     * @param userCodes
     * @return
     */
    @Override
    public List<UserInfoVO> getByCodes(List<String> userCodes) {
        return this.userDao.getByCodes(userCodes);
    }

    /**
     * 修改用户头像
     *
     * @param headPic 新头像url
     * @param code    用户code
     * @return
     */
    @Override
    public Integer updateUserHeadPic(String headPic, String code) {
        // 删除原头像
        UserInfoVO infoVO = getByCode(code);
        if (null != infoVO.getHeadPic() && !"".equals(infoVO.getHeadPic())){
            fileService.deleteByName(infoVO.getHeadPic());
        }
        // 更新头像
        UserInfoPO userInfoPO = new UserInfoPO();
        userInfoPO.setCode(code);
        userInfoPO.setHeadPic(headPic);
        return update(userInfoPO);
    }

    @Override
    public SignVO getUserSign(String code) {
        SignVO signVO = new SignVO();
        UserInfoPO byCode = getByCode(code);
        try {
            if (byCode != null) {
                signVO = this.getSignNumber(byCode);
                signVO.setOld(byCode.getOld());
                //根据连续签到天数告诉用户奖励
                Integer enumValue = signVO.getSignNum() > 5 ? 5 : signVO.getSignNum();
                String todayG = EnumUtil.getFieldBy(SignTodayEnum::getReward, Enum::ordinal, enumValue);
                String otherG = EnumUtil.getFieldBy(SignTomorrowEnum::getReward, Enum::ordinal, enumValue);
                signVO.setTodayGet(todayG);
                signVO.setOtherGet(otherG);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return signVO;
    }

    /**
     * 连续签到天数判断
     * 签到时间=昨天or今天。签到天数=数据库存储天数
     * 签到时间！=（昨天or今天)。签到天数=0
     */
    public SignVO getSignNumber(UserInfoPO infoPO) {
        SignVO signVO = new SignVO();
        // 连续签到天数或者上次签到时间为null时，则从未签到
        if (null == infoPO.getSignNumber() || null == infoPO.getSignTime()) {
            UserInfoPO updatePO = new UserInfoPO();
            updatePO.setCode(infoPO.getCode());
            updatePO.setSignNumber(0);
            this.userDao.update(updatePO);
            signVO.setSignNum(0);
            signVO.setTodaySign(false);
        }else {
            // 连续签到天数
            Integer signNumber = infoPO.getSignNumber();
            // 获取签到时间
            String signTime = DateUtil.format(infoPO.getSignTime(), "yyyy-MM-dd");
            // 今天
            String today = DateUtil.format(new Date(), "yyyy-MM-dd");
            // 昨天
            DateTime yesterdayTime = DateUtil.yesterday();
            String yesterday = DateUtil.format(yesterdayTime, "yyyy-MM-dd");
            if (!signTime.equals(yesterday) && !signTime.equals(today)) {
                signNumber = 0;
                UserInfoPO updatePO = new UserInfoPO();
                updatePO.setCode(infoPO.getCode());
                updatePO.setSignNumber(0);
                this.userDao.update(updatePO);
            }
            //今日是否签到
            if (signTime.equals(today)) {
                signVO.setTodaySign(true);
            } else {
                signVO.setTodaySign(false);
            }
            // 连续签到天数
            signVO.setSignNum(signNumber);
        }
        return signVO;
    }

}
